package push

import (
	"context"
	"fmt"
	"sync"

	"jgt-sdk/asapi"
	"jgt-sdk/utils"
)

var (
	internalHandle *Handle
	once           sync.Once
)

// InitPush 初始化推送服务
func InitPush(as *asapi.APIHandle) *Handle {
	once.Do(func() {
		internalHandle = &Handle{
			as:       as,
			identify: "PUSH",
			lock:     new(sync.RWMutex),
		}
	})
	return internalHandle
}

// GetHandle 获取推送服务
func GetHandle() *Handle {
	return GetHandleWithTraceID("")
}

// GetHandleWithTraceID 获取推送服务
func GetHandleWithTraceID(traceID string) *Handle {
	if traceID == "" {
		traceID = utils.UUIDString()
	}
	handle := *internalHandle
	handle.traceID = traceID
	return &handle
}

// Handle 运营服务
type Handle struct {
	as       *asapi.APIHandle
	identify string
	host     string
	traceID  string
	lock     *sync.RWMutex
}

func (a *Handle) getHost() string {
	a.lock.RLock()
	host := a.host
	a.lock.RUnlock()
	if host == "" {
		a.lock.Lock()
		defer a.lock.Unlock()
		v, err := a.as.GetServiceHost(a.identify)
		if err == nil && v != "" {
			host = v
			a.host = v
		}
	}
	return host
}

func (a *Handle) getContext() context.Context {
	return utils.NewTraceIDContext(context.Background(), a.traceID)
}

// GetURL 获取URL
func (a *Handle) GetURL(router string) (string, error) {
	host := a.getHost()
	if host == "" {
		return "", fmt.Errorf("无效的Host")
	}
	return utils.RequestURL(host, router), nil
}

// NewExtraItem 创建推送扩展项实例
func NewExtraItem(typ, nativeURI string, extras ...interface{}) *ExtraItem {
	item := &ExtraItem{
		Type:      typ,
		NativeURI: nativeURI,
	}

	if len(extras) > 0 {
		item.Extras = extras[0]
	}

	return item
}

// ExtraItem 推送扩展项
type ExtraItem struct {
	Type      string      `json:"type"`       // 业务类型
	NativeURI string      `json:"native_uri"` // 跳转的原生URI
	Extras    interface{} `json:"extras"`     // 扩展参数(用于移动端展示)
}

// PushToAlias 推送到别名
// title 标题
// alert 通知内容
// collapseID 客户端折叠ID，可为空
// extras 扩展参数
// aliases 别名（用户ID）
func (a *Handle) PushToAlias(title, alert, collapseID string, extras *ExtraItem, aliases ...string) error {
	urlStr, err := a.GetURL("/api/v1/push/alias")
	if err != nil {
		return err
	}

	param := map[string]interface{}{
		"aliases":     aliases,
		"title":       title,
		"alert":       alert,
		"collapse_id": collapseID,
	}
	if extras != nil {
		param["extras"] = extras
	}

	return utils.PostJSONWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, nil)
}

// PushToTag 推送到标签
// title 标题
// alert 通知内容
// collapseID 客户端折叠ID，可为空
// extras 扩展参数
// tags 标签（用户类型）
func (a *Handle) PushToTag(title, alert, collapseID string, extras *ExtraItem, tags ...string) error {
	urlStr, err := a.GetURL("/api/v1/push/tag")
	if err != nil {
		return err
	}

	param := map[string]interface{}{
		"tags":        tags,
		"title":       title,
		"alert":       alert,
		"collapse_id": collapseID,
	}
	if extras != nil {
		param["extras"] = extras
	}

	return utils.PostJSONWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, nil)
}

// PushToAll 推送到全部设备
// title 标题
// alert 通知内容
// collapseID 客户端折叠ID，可为空
// extras 扩展参数
func (a *Handle) PushToAll(title, alert, collapseID string, extras *ExtraItem) error {
	urlStr, err := a.GetURL("/api/v1/push/all")
	if err != nil {
		return err
	}

	param := map[string]interface{}{
		"title":       title,
		"alert":       alert,
		"collapse_id": collapseID,
	}
	if extras != nil {
		param["extras"] = extras
	}

	return utils.PostJSONWithToken(a.getContext(), urlStr, a.as.GetTokenHandle().Get, param, nil)
}
